home *** CD-ROM | disk | FTP | other *** search
/ CD Ware Multimedia 1994 November / Cd Ware (Nro. 2) - Epimundo.iso / OS2 / PC2_170.ZIP / SOURCE.ZIP / Source / Pc2Hook.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-01  |  26.1 KB  |  383 lines

  1. /***********************************************************************\
  2.  *                                PC2.c                                *
  3.  *              Copyright (C) by Stangl Roman, 1993, 1994              *
  4.  * This Code may be freely distributed, provided the Copyright isn't   *
  5.  * removed.                                                            *
  6.  *                                                                     *
  7.  * Pc2Hook.c    Hook the input queue to filter certain messages.       *
  8.  *                                                                     *
  9. \***********************************************************************/
  10.  
  11. static char RCSID[]="@(#) $Header: Pc2Hook.c Version 1.70 06,1994 $ (LBL)";
  12.  
  13. #define         _FILE_  "PC/2 - PC2Hook.c V1.70"
  14.  
  15. #include        "PC2.h"                 /* User include files */
  16. #include        "Error.h"
  17.  
  18. /*--------------------------------------------------------------------------------------*\
  19.  * The following functions are exported in PC2Hook.def                                  *
  20. \*--------------------------------------------------------------------------------------*/
  21. void EXPENTRY   PC2DLL_SetParameters(void);
  22. BOOL EXPENTRY   PC2DLL_Hook(HAB hab, PQMSG pqmsg, ULONG option);
  23.  
  24. /*--------------------------------------------------------------------------------------*\
  25.  * The following datastructures are exported in PC2Hook.def                             *
  26. \*--------------------------------------------------------------------------------------*/
  27. HOOKPARAMETERS  HookParameters;         /* Central control structure for PC/2 */
  28. KEYDATA         KeyData[KEYDATACOUNT]={ /* Hotkeys defined within PC/2 */
  29.                     {KC_CTRL, '0', FALSE, NULL}, {KC_CTRL, '1', FALSE, NULL}, {KC_CTRL, '2', FALSE, NULL},
  30.                     {KC_CTRL, '3', FALSE, NULL}, {KC_CTRL, '4', FALSE, NULL}, {KC_CTRL, '5', FALSE, NULL},
  31.                     {KC_CTRL, '6', FALSE, NULL}, {KC_CTRL, '7', FALSE, NULL}, {KC_CTRL, '8', FALSE, NULL},
  32.                     {KC_CTRL, '9', FALSE, NULL},
  33.                     {KC_CTRL, 'A', FALSE, NULL}, {KC_CTRL, 'B', FALSE, NULL}, {KC_CTRL, 'C', FALSE, NULL},
  34.                     {KC_CTRL, 'D', FALSE, NULL}, {KC_CTRL, 'E', FALSE, NULL}, {KC_CTRL, 'F', FALSE, NULL},
  35.                     {KC_CTRL, 'G', FALSE, NULL}, {KC_CTRL, 'H', FALSE, NULL}, {KC_CTRL, 'I', FALSE, NULL},
  36.                     {KC_CTRL, 'J', FALSE, NULL}, {KC_CTRL, 'K', FALSE, NULL}, {KC_CTRL, 'L', FALSE, NULL},
  37.                     {KC_CTRL, 'M', FALSE, NULL}, {KC_CTRL, 'N', FALSE, NULL}, {KC_CTRL, 'O', FALSE, NULL},
  38.                     {KC_CTRL, 'P', FALSE, NULL}, {KC_CTRL, 'Q', FALSE, NULL}, {KC_CTRL, 'R', FALSE, NULL},
  39.                     {KC_CTRL, 'S', FALSE, NULL}, {KC_CTRL, 'T', FALSE, NULL}, {KC_CTRL, 'U', FALSE, NULL},
  40.                     {KC_CTRL, 'V', FALSE, NULL}, {KC_CTRL, 'W', FALSE, NULL}, {KC_CTRL, 'X', FALSE, NULL},
  41.                     {KC_CTRL, 'Y', FALSE, NULL}, {KC_CTRL, 'Z', FALSE, NULL},
  42.                     {KC_ALT, '0', FALSE, NULL}, {KC_ALT, '1', FALSE, NULL}, {KC_ALT, '2', FALSE, NULL},
  43.                     {KC_ALT, '3', FALSE, NULL}, {KC_ALT, '4', FALSE, NULL}, {KC_ALT, '5', FALSE, NULL},
  44.                     {KC_ALT, '6', FALSE, NULL}, {KC_ALT, '7', FALSE, NULL}, {KC_ALT, '8', FALSE, NULL},
  45.                     {KC_ALT, '9', FALSE, NULL},
  46.                     {KC_ALT, 'A', FALSE, NULL}, {KC_ALT, 'B', FALSE, NULL}, {KC_ALT, 'C', FALSE, NULL},
  47.                     {KC_ALT, 'D', FALSE, NULL}, {KC_ALT, 'E', FALSE, NULL}, {KC_ALT, 'F', FALSE, NULL},
  48.                     {KC_ALT, 'G', FALSE, NULL}, {KC_ALT, 'H', FALSE, NULL}, {KC_ALT, 'I', FALSE, NULL},
  49.                     {KC_ALT, 'J', FALSE, NULL}, {KC_ALT, 'K', FALSE, NULL}, {KC_ALT, 'L', FALSE, NULL},
  50.                     {KC_ALT, 'M', FALSE, NULL}, {KC_ALT, 'N', FALSE, NULL}, {KC_ALT, 'O', FALSE, NULL},
  51.                     {KC_ALT, 'P', FALSE, NULL}, {KC_ALT, 'Q', FALSE, NULL}, {KC_ALT, 'R', FALSE, NULL},
  52.                     {KC_ALT, 'S', FALSE, NULL}, {KC_ALT, 'T', FALSE, NULL}, {KC_ALT, 'U', FALSE, NULL},
  53.                     {KC_ALT, 'V', FALSE, NULL}, {KC_ALT, 'W', FALSE, NULL}, {KC_ALT, 'X', FALSE, NULL},
  54.                     {KC_ALT, 'Y', FALSE, NULL}, {KC_ALT, 'Z', FALSE, NULL} };
  55.  
  56. /*--------------------------------------------------------------------------------------*\
  57.  * The following datastructures are local for in PC2Hook.dll                            *
  58. \*--------------------------------------------------------------------------------------*/
  59. ULONG                   ulMoveFlag;     /* xxxxxxxx (<-Bit 0)
  60.                                                   | Move all windows in x direction
  61.                                                  |  Move in -x direction
  62.                                                 |   Move in y direction
  63.                                                |    Move in -y direction
  64.                                               |     Click required to move */
  65. LONG                    SlidingXFactor; /* Slide in x direction in pixels */
  66. LONG                    SlidingYFactor; /* Slide in y direction in pixels */
  67.                                         /* Hotkeys defined for PS/2 */
  68. QUERYRECFROMRECT        QueryRect;      /* Rectangle to query underlaying containers */
  69.  
  70. /*--------------------------------------------------------------------------------------*\
  71.  * This procedure saves the data used in the PC/2 main procedure for use within the     *
  72.  * DLL.                                                                                 *
  73.  * Req:                                                                                 *
  74.  *      none                                                                            *
  75.  * Returns:                                                                             *
  76.  *      none                                                                            *
  77. \*--------------------------------------------------------------------------------------*/
  78. void EXPENTRY   PC2DLL_SetParameters(void)
  79. {
  80.                                         /* Initialize to query the topmost underlaying
  81.                                            container, that is partially hit by a rectangle
  82.                                            around the pointer */
  83. QueryRect.cb=sizeof(QUERYRECFROMRECT);
  84. QueryRect.fsSearch=CMA_PARTIAL | CMA_ZORDER;
  85. }
  86.  
  87. /*--------------------------------------------------------------------------------------*\
  88.  * This procedure implements the hook of the input queue.        .                      *
  89.  * Req:                                                                                 *
  90.  *      PQMSG ......... Pointer to system QMSG structure                                *
  91.  * Returns:                                                                             *
  92.  *      FALSE ......... OS/2 should process QMSG in the normal way                      *
  93. \*--------------------------------------------------------------------------------------*/
  94. BOOL EXPENTRY   PC2DLL_Hook(HAB hab, PQMSG pqmsg, ULONG option)
  95. {
  96. static ULONG    ulButtonDown=0;         /* Last button down on PM, either WM_BUTTON1DOWN
  97.                                            or WM_BUTTON2DOWN or 0 if pointer is not over
  98.                                            PM */
  99.  
  100.                                         /* Return if mouse is captured */
  101. if(WinQueryCapture(HWND_DESKTOP)!=NULLHANDLE) return(FALSE);
  102. /*                                                                                      *\
  103.  * Here we catch mouse button clicks on the PM to be able to send PC/2 a message when   *
  104.  * it should display the window list, because the window list is only displayed if the  *
  105.  * mouse is clicked on the WPS (not displaying the window list on PM).                  *
  106.  * The window list is invoked (like on the WPS) when one mouse button is down, and the  *
  107.  * other mouse button is pressed down too, but only if we are over PM.                  *
  108. \*                                                                                      */
  109.                                         /* If one button is down and none was down before
  110.                                            save it because window list requires second button
  111.                                            down too */
  112. if((pqmsg->msg==WM_BUTTON1DOWN) && (ulButtonDown!=WM_BUTTON2DOWN))
  113.     ulButtonDown=WM_BUTTON1DOWN;
  114. if((pqmsg->msg==WM_BUTTON2DOWN) && (ulButtonDown!=WM_BUTTON1DOWN))
  115.     ulButtonDown=WM_BUTTON2DOWN;
  116.                                         /* If one button goes up ignore previous buttons down */
  117. if((pqmsg->msg==WM_BUTTON1UP) || (pqmsg->msg==WM_BUTTON2UP)) ulButtonDown=0;
  118. if((pqmsg->hwnd!=HookParameters.hwndDesktop) && (pqmsg->msg==WM_MOUSEMOVE))
  119.     ulButtonDown=0;                     /* If the mouse is not over PM reset window list flag */
  120.                                         /* If the user holds down both mouse buttons on PM display Window List */
  121. if((pqmsg->msg==WM_BUTTON1DOWN) && (ulButtonDown==WM_BUTTON2DOWN))
  122.     {
  123.     ulButtonDown=0;
  124.     WinSendMsg(HookParameters.hwndPC2, WM_WINDOWLIST, MPFROMLONG(pqmsg->mp1), NULL);
  125.     return(TRUE);                       /* Don't pass this message to next hook in chain. */
  126.     }
  127. if((pqmsg->msg==WM_BUTTON2DOWN) && (ulButtonDown==WM_BUTTON1DOWN))
  128.     {
  129.     ulButtonDown=0;
  130.     WinSendMsg(HookParameters.hwndPC2, WM_WINDOWLIST, MPFROMLONG(pqmsg->mp1), NULL);
  131.     return(TRUE);                       /* Don't pass this message to next hook in chain. */
  132.     }
  133. /*                                                                                      *\
  134.  * Here we catch all WM_BUTTON2DOWN messages. If it was clicked on any window's         *
  135.  * titlebar then set this window to the bottom of the Desktop. WM_BUTTON2DOWN is used   *
  136.  * to prevent the moving frame to be drawn (which is the default action of a            *
  137.  * WM_BUTTON2DOWN message on a window's titlebar.                                       *
  138.  * This function using WM_BUTTON2DBLCLK was first implemented by Robert Mahoney's       *
  139.  * utiltiy WinBack, modified by Rolf Knebel to add this functionality to PC/2. However  *
  140.  * using a doubleclick with mouse button 2 has the drawback that the window is brought  *
  141.  * into the foreground first (because clicking on the titlebar activates a window) and  *
  142.  * then moved to the bottom (causing many unnecessary drawings).                        *
  143. \*                                                                                      */
  144. if((pqmsg->msg==WM_BUTTON2DOWN) && (HookParameters.ulStatusFlag & BUTTON2ZORDER))
  145.     {
  146.     HWND    hwndApplicationParent=WinQueryWindow(pqmsg->hwnd, QW_PARENT);
  147.  
  148.                                         /* If we click on a titlebar the current window handle
  149.                                            equals the parent's titlebar window handle */
  150.     if(pqmsg->hwnd==WinWindowFromID(hwndApplicationParent, FID_TITLEBAR))
  151.         {                               /* Set it to the bottom of all windows */
  152.         WinSetWindowPos(hwndApplicationParent, HWND_BOTTOM, 0, 0, 0, 0, SWP_ZORDER|SWP_DEACTIVATE);
  153.         return(TRUE);                   /* Don't pass this message to next hook in chain. */
  154.         }
  155.     }
  156. /*                                                                                      *\
  157.  * Here we catch all WM_CHAR messages filtering them for hotkeys. Found hotkeys are     *
  158.  * sent to PC/2.                                                                        *
  159. \*                                                                                      */
  160. if(pqmsg->msg == WM_CHAR)
  161.     {
  162.     USHORT  usFlags=SHORT1FROMMP(pqmsg->mp1)&(KC_CTRL|KC_ALT);
  163.     USHORT  usCh=SHORT1FROMMP(pqmsg->mp2);
  164.  
  165.                                         /* Convert any non numeric character to uppercase */
  166.     if((usCh>(USHORT)'9') || (usCh<(USHORT)'0')) usCh &= ~0x20;
  167.     if((usFlags==KC_CTRL) || (usFlags==KC_ALT))
  168.         {
  169.         KEYDATA *pKeyData=KeyData;
  170.         ULONG   ulKeyDataIndex=0;
  171.                                         /* Now try to find the key */
  172.         for( ;ulKeyDataIndex<=KEYDATACOUNT; ulKeyDataIndex++, pKeyData++)
  173.             if((pKeyData->usFlags==usFlags) && (pKeyData->usCh==usCh))
  174.                 {
  175.                 if(pKeyData->bUsed==TRUE)
  176.                     {
  177.                     WinPostMsg(HookParameters.hwndPC2, WM_HOTKEY,
  178.                         MPFROM2SHORT(usFlags, usCh), MPFROMLONG(ulKeyDataIndex));
  179.                     return(TRUE);       /* Don't pass this message to next hook in chain. */
  180.                     }
  181.                 else break;             /* If our key is not used we don't need any
  182.                                            further search */
  183.                 }
  184.         }
  185.     }
  186. /*                                                                                      *\
  187.  * Here we catch mouse button 1 clicks, either the move the Desktop or to display the   *
  188.  * Popup-Menu.                                                                          *
  189. \*                                                                                      */
  190. while(pqmsg->msg==HookParameters.ulClickFlag)
  191.     {
  192. /*                                                                                      *\
  193.  * If the user clicked on at least one of the surrounding rows or columns of the        *
  194.  * display, we shift the physical Desktop on the virtual Desktop. The flag MOVED4CLICK  *
  195.  * is set, if the user click on the display borders.                                    *
  196. \*                                                                                      */
  197.     if(ulMoveFlag & MOVED4CLICK)
  198.         {
  199.         WinSendMsg(HookParameters.hwndPC2, WM_MOVEREQUEST,
  200.             MPFROM2SHORT(pqmsg->ptl.x, pqmsg->ptl.y), MPFROMLONG(ulMoveFlag));
  201.         ulMoveFlag&=~MOVED4CLICK;       /* Reset flag, because only a move before
  202.                                            a click may set it */
  203.         return(TRUE);                   /* Don't pass this message to next hook in chain. */
  204.         }
  205. /*                                                                                      *\
  206.  * If the user clicked on the WPS or PM window, send PC/2 a message to display the      *
  207.  * Popup-Menu.                                                                          *
  208. \*                                                                                      */
  209.     if(pqmsg->hwnd==HookParameters.hwndWPS)
  210.         {                               /* The user clicked on WPS "Desktop" window.
  211.                                            We construct a small rectangle around the
  212.                                            current position of the pointer */
  213.         QueryRect.rect.xLeft=pqmsg->ptl.x;
  214.         QueryRect.rect.xRight=pqmsg->ptl.x+1;
  215.         QueryRect.rect.yBottom=pqmsg->ptl.y;
  216.         QueryRect.rect.yTop=pqmsg->ptl.y+1;
  217.         if(WinSendMsg(HookParameters.hwndWPS, CM_QUERYRECORDFROMRECT,
  218.             MPFROMLONG(CMA_FIRST), &QueryRect)==NULL)
  219.                                         /* If no container is under the rectangle of the
  220.                                            mouse pointer, we can display our Popup-Menu.
  221.                                            The type of container is unknown, but because
  222.                                            we test only on the WPS, they should usually
  223.                                            be the icons (but not the minimized programs,
  224.                                            which are windows with a different window handle). */
  225.                                         /* Pass the pointer position in coordinates relative
  226.                                            to the window and the handle of that window.
  227.                                            The coordinates must be translated from that
  228.                                            window to the display */
  229.             {
  230.             WinSendMsg(HookParameters.hwndPC2, WM_POPUPMENU,
  231.                 MPFROMLONG(pqmsg->mp1), MPFROMHWND(pqmsg->hwnd));
  232.             return(TRUE);               /* Don't pass this message to next hook in chain. */
  233.             }
  234.         break;                          /* If clicked on an container, pass message to WPS */
  235.         }
  236.     if(pqmsg->hwnd==HookParameters.hwndDesktop)
  237.         {                               /* The user clicked on the PM "Desktop" window.
  238.                                            If the WPS isn't installed we only get the PM
  239.                                            windows. We can now display our Popup-Menu.
  240.                                            Pass the pointer position in coordinates relative
  241.                                            to the window and the handle of that window.
  242.                                            The coordinates must be translated from that
  243.                                            window to the display */
  244.         WinSendMsg(HookParameters.hwndPC2, WM_POPUPMENU,
  245.             MPFROMLONG(pqmsg->mp1), MPFROMHWND(pqmsg->hwnd));
  246.         return(TRUE);                   /* Don't pass this message to next hook in chain. */
  247.         }
  248.     break;                              /* Break out of while loop */
  249.     }
  250. /*                                                                                      *\
  251.  * If enabled, here we catch all mouse movements, to set the window under the mouse     *
  252.  * pointer as the active one, if it isn't currently active or the window list or        *
  253.  * optionally the Desktop window.                                                       *
  254. \*                                                                                      */
  255. while((pqmsg->msg==WM_MOUSEMOVE) && (HookParameters.ulStatusFlag & SLIDINGFOCUS))
  256.     {                                   /* If enabled, use sliding focus to activate window
  257.                                            under the mouse pointer (with some exceptions).
  258.                                            Caution! Menus have a class WC_MENU, but their
  259.                                            parent is not the frame window WC_FRAME but the
  260.                                            Desktop itself. */
  261.     static UCHAR    ucClassname[7];     /* Window class f.e. #1 for WC_FRAME */
  262.     static UCHAR    ucWindowText[33];   /* Window name f.e. OS/2 2.0 Desktop */
  263.     static HWND     hwndActive;         /* Window handle of active frame class window on Desktop */
  264.     static HWND     hwndApplication;    /* Window handle of application under mouse pointer */
  265.                                         /* Window handle of applications parent window */
  266.     static HWND     hwndApplicationParent;
  267.  
  268.                                         /* Query the currently active window, where HWND_DESKTOP
  269.                                            is the parent window. It will be a WC_FRAME class
  270.                                            window */
  271.     hwndActive=WinQueryActiveWindow(HWND_DESKTOP);
  272.     WinQueryWindowText(hwndActive, sizeof(ucWindowText), ucWindowText);
  273.                                         /* Don't switch away from the WC_FRAME class tasklist */
  274.     if(!strcmp(ucWindowText, HookParameters.ucWindowListName)) break;
  275.     hwndApplication=pqmsg->hwnd;        /* Get message target window */
  276.     if((hwndApplication==HookParameters.hwndDesktop) || (hwndApplication==HookParameters.hwndWPS))
  277.         break;                          /* If the window under the mouse pointer is one of the
  278.                                            Desktops, don't do any changes */
  279.                                         /* Get parent window of current window */
  280.     hwndApplicationParent=WinQueryWindow(hwndApplication, QW_PARENT);
  281.     while(hwndApplicationParent!=HookParameters.hwndDesktop)
  282.         {                               /* Loop until we get the Desktop window handle. The
  283.                                            previous child window of the Desktop is then the
  284.                                            WC_FRAME class window of the point under the mouse
  285.                                            pointer which is not the Desktop. */
  286.         hwndApplication=hwndApplicationParent;
  287.         hwndApplicationParent=WinQueryWindow(hwndApplication, QW_PARENT);
  288.         }
  289.                                         /* Query the class of the frame window of the
  290.                                            designated target of WM_MOUSEMOVE */
  291.     WinQueryClassName(hwndApplication, sizeof(ucClassname), ucClassname);
  292.                                         /* Query the frame window name of the designated
  293.                                            target of WM_MOUSEMOVE */
  294.     WinQueryWindowText(hwndApplication, sizeof(ucWindowText), ucWindowText);
  295.     while(TRUE)
  296.         {                               /* Sort with expected descending probability, to avoid
  297.                                            unnecessary cpu load */
  298.                                         /* Don't switch if previous windows equals current one */
  299.         if(hwndActive==hwndApplication) break;
  300.                                         /* Only switch to WC_FRAME class windows */
  301.         if(strcmp(ucClassname, "#1")) break;
  302.                                         /* Don't switch to the WC_FRAME class window of PC/2 */
  303.         if(strstr(ucWindowText, "PC/2")) break;
  304.         if(HookParameters.ulStatusFlag & PRESERVEZORDER)
  305.             {                           /* Change focus, but preserve Z-order */
  306.                                         /* Don't send WM_ACTIVATE to window with new focus */
  307.             WinFocusChange(HWND_DESKTOP, pqmsg->hwnd, FC_NOSETACTIVE);
  308.                                         /* Activate new window */
  309.             WinPostMsg(hwndApplication, WM_ACTIVATE, MPFROMSHORT(TRUE), MPFROMHWND(pqmsg->hwnd));
  310.             }
  311.         else                            /* Now switch to the new frame window, causing
  312.                                            a new Z-order. It will generate all messages
  313.                                            of deactivating old and activating the
  314.                                            new window. */
  315.             WinFocusChange(HWND_DESKTOP, pqmsg->hwnd, 0);
  316.         return(TRUE);                   /* We changed the focus, don't pass this message to
  317.                                            the next hook in the chain */
  318.         }
  319.     break;                              /* Exit loop now */
  320.     }
  321. /*                                                                                      *\
  322.  * If enabled, here we catch all mouse movements that are on the surrounding rows and   *
  323.  * columns of the physical Desktop, to adjust the position of the physical Desktop      *
  324.  * within the virtual Desktop.                                                          *
  325. \*                                                                                      */
  326. while((pqmsg->msg==WM_MOUSEMOVE) && (HookParameters.ulStatusFlag & VIRTUALDESKTOP))
  327.     {
  328.     ulMoveFlag=0;
  329.     if(pqmsg->ptl.x<=0)
  330.         {                               /* If we are on the left border of our physical
  331.                                            Desktop, move all windows right as we shift
  332.                                            it leftwards on the virtual Desktop */
  333.         ulMoveFlag|=MOVEXR;
  334.                                         /* If we're in the lower left corner, also move
  335.                                            all windows up and shift downwards on the
  336.                                            virtual Desktop */
  337.         if(pqmsg->ptl.y<=HookParameters.LLHotBorder.y) ulMoveFlag|=MOVEYU;
  338.                                         /* If we're in the upper left corner, also move
  339.                                            all windows down and shift upwards on the
  340.                                            virtual Desktop */
  341.         if(pqmsg->ptl.y>=HookParameters.URHotBorder.y) ulMoveFlag|=MOVEYD;
  342.         }
  343.     if(pqmsg->ptl.x>=HookParameters.DesktopSize.x-1)
  344.         {                               /* If we are on the right border of our physical
  345.                                            Desktop, move all windows left as we shift
  346.                                            it rightwards on the virtual Desktop */
  347.         ulMoveFlag|=MOVEXL;
  348.         if(pqmsg->ptl.y<=HookParameters.LLHotBorder.y) ulMoveFlag|=MOVEYU;
  349.         if(pqmsg->ptl.y>=HookParameters.URHotBorder.y) ulMoveFlag|=MOVEYD;
  350.         }
  351.     if(pqmsg->ptl.y<=0)
  352.         {                               /* If we are on the bottom border of our physical
  353.                                            Desktop, move all windows up as we shift
  354.                                            it downwards on the virtual Desktop */
  355.         ulMoveFlag|=MOVEYU;
  356.         if(pqmsg->ptl.x<=HookParameters.LLHotBorder.x) ulMoveFlag|=MOVEXR;
  357.         if(pqmsg->ptl.x>=HookParameters.URHotBorder.x) ulMoveFlag|=MOVEXL;
  358.         }
  359.     if(pqmsg->ptl.y>=HookParameters.DesktopSize.y-1)
  360.         {                               /* If we are on the top border of our physical
  361.                                            Desktop, move all windows down as we shift
  362.                                            it upwards on the virtual Desktop */
  363.         ulMoveFlag|=MOVEYD;
  364.         if(pqmsg->ptl.x<=HookParameters.LLHotBorder.x) ulMoveFlag|=MOVEXR;
  365.         if(pqmsg->ptl.x>=HookParameters.URHotBorder.x) ulMoveFlag|=MOVEXL;
  366.         }
  367.     if(ulMoveFlag==0) break;            /* If there is no window to move, don't do any
  368.                                            further processing and exit loop. As no flags
  369.                                            are set, the click loop will not find 
  370.                                            the necessity to move */
  371.     ulMoveFlag|=MOVED4CLICK;            /* We're now about to move, but if the user
  372.                                            selected to click before move, we exit this
  373.                                            loop with the flags set. The click loop
  374.                                            will then use these flags */
  375.     if(HookParameters.ulStatusFlag & CLICK2MOVE) break;
  376.     WinPostMsg(HookParameters.hwndPC2, WM_MOVEREQUEST,
  377.         MPFROM2SHORT(pqmsg->ptl.x, pqmsg->ptl.y), MPFROMLONG(ulMoveFlag));
  378.     return(TRUE);                       /* Exit from loop */
  379.     }
  380. return(FALSE);                          /* Process the message in the normal way */
  381. }
  382.  
  383.